// Copyright 2013 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"time"
)

import (
	"walk"
	. "walk/declarative"
)

func main() {
	//声明一个全局的主窗体对象
	var mw *walk.MainWindow
	//声明一个全局的文本框对象
	var outTE *walk.TextEdit
	//动物结构体的实例
	animal := new(Animal)
	//窗口主体的设置
	if _, err := (MainWindow{
		//绑定到声明的主窗口
		AssignTo: &mw,
		Title:    "Walk Data Binding Example",
		MinSize:  Size{300, 200},
		Layout:   VBox{},
		Children: []Widget{
			PushButton{
				Text: "Edit Animal",
				OnClicked: func() {
					//命令按钮的动作:获取一个新的窗口对象
					cmd, err := RunAnimalDialog(mw, animal);
					if err != nil {
						log.Print(err)
					}
					//如果返回的按钮结果是ok,就进行下一步计算
					if cmd == walk.DlgCmdOK {
						//将动物实例的数据回写进文本框
						outTE.SetText(fmt.Sprintf("%+v", animal))
					}
				},
			},
			//加入一行文本标签
			Label{
				Text: "animal:",
			},
			//下一行为文本框
			TextEdit{
				//文本框绑定到已声明的对象
				AssignTo: &outTE,
				//设置为只读
				ReadOnly: true,
				//默认显示文字为动物实体数据
				Text:     fmt.Sprintf("%+v", animal),
			},
		},
	}.Run()); err != nil {
		log.Fatal(err)
	}
}

//动物结构体,用来存储子窗口的数据
type Animal struct {
	Name          string
	ArrivalDate   time.Time
	SpeciesId     int
	Speed         int
	Sex           Sex
	Weight        float64
	PreferredFood string
	Domesticated  bool
	Remarks       string
	Patience      time.Duration
}
//返回耐心时间字段的数据
func (a *Animal) PatienceField() *DurationField {
	return &DurationField{&a.Patience}
}

//种类
type Species struct {
	Id   int
	Name string
}
//已知种类的指针数组
func KnownSpecies() []*Species {
	return []*Species{
		{1, "Dog"},
		{2, "Cat"},
		{3, "Bird"},
		{4, "Fish"},
		{5, "Elephant"},
	}
}

//持续时间结构体
type DurationField struct {
	p *time.Duration
}
//是否能设置时间
func (*DurationField) CanSet() bool       { return true }
//获取时间字符串
func (f *DurationField) Get() interface{} { return f.p.String() }
//将字符串设置为时间
func (f *DurationField) Set(v interface{}) error {
	x, err := time.ParseDuration(v.(string))
	if err == nil {
		*f.p = x
	}
	return err
}

//声明性别类型
type Sex byte
//初始化性别常数
const (
	SexMale Sex = 1 + iota
	SexFemale
	SexHermaphrodite
)

//返回一个窗口的运行结果
func RunAnimalDialog(owner walk.Form, animal *Animal) (int, error) {
	//声明一些窗口全局对象,比如窗口对象
	var dlg *walk.Dialog
	//数据绑定器
	var db *walk.DataBinder
	//错误呈现对象
	var ep walk.ErrorPresenter
	//两个按钮
	var acceptPB, cancelPB *walk.PushButton

	return Dialog{
		//绑定到全局对象
		AssignTo:      &dlg,
		Title:         "Animal Details",
		//设置默认按钮
		DefaultButton: &acceptPB,
		//设置取消按钮
		CancelButton:  &cancelPB,
		//设置窗体的数据绑定器
		DataBinder: DataBinder{
			//绑定到声明的数据对象
			AssignTo:       &db,
			//设置整体的数据源
			DataSource:     animal,
			ErrorPresenter: ErrorPresenterRef{&ep},
		},
		MinSize: Size{300, 300},
		Layout:  VBox{},
		Children: []Widget{
			//复合布局对象,用来封装第二层的布局设置
			Composite{
				//二层布局是表格,设置成两列
				Layout: Grid{Columns: 2},
				Children: []Widget{
					Label{
						//第一列为标签
						Text: "Name:",
					},
					LineEdit{
						//第二列为文本框,数据绑定到Animal实体的Name属性字段
						Text: Bind("Name"),
					},

					Label{
						Text: "Arrival Date:",
					},
					DateEdit{
						Date: Bind("ArrivalDate"),
					},

					Label{
						Text: "Species:",
					},
					//下拉列表框的用法
					ComboBox{
						//绑定返回值对应的字段,和验证模型
						Value:         Bind("SpeciesId", SelRequired{}),
						//设置绑定的字段
						BindingMember: "Id",
						//设置显示的字段
						DisplayMember: "Name",
						//设置数据模型的值
						Model:         KnownSpecies(),

					},

					Label{
						Text: "Speed:",
					},
					Slider{
						Value: Bind("Speed"),
					},
					//单选框组的设置
					RadioButtonGroupBox{
						//占用的列数
						ColumnSpan: 2,
						Title:      "Sex",
						//子布局模式
						Layout:     HBox{},
						DataMember: "Sex",
						//单选框数组
						Buttons: []RadioButton{
							{Text: "Male", Value: SexMale},
							{Text: "Female", Value: SexFemale},
							{Text: "Hermaphrodite", Value: SexHermaphrodite},
						},
					},

					Label{
						Text: "Weight:",
					},
					//第二列为数字文本框
					NumberEdit{
						//绑定字段及数值范围
						Value:    Bind("Weight", Range{0.01, 9999.99}),
						//后缀显示
						Suffix:   " kg",
						//小数位数
						Decimals: 2,
					},

					Label{
						Text: "Preferred Food:",
					},
					//复合框设置,兼具下拉列表及文本框
					ComboBox{
						//启用输入
						Editable: true,
						Value:    Bind("PreferredFood"),
						//数据源模型的设置,必须是数组
						Model:    []string{"Fruit", "Grass", "Fish", "Meat"},
					},

					Label{
						Text: "Domesticated:",
					},
					CheckBox{
						//绑定到一个布林字段
						Checked: Bind("Domesticated"),
					},
					//设置一个竖向空间,占用2列,大小为8像素
					VSpacer{
						ColumnSpan: 2,
						Size:       8,
					},
					//整行显示标签,占用2列
					Label{
						ColumnSpan: 2,
						Text:       "Remarks:",
					},
					TextEdit{
						ColumnSpan: 2,
						MinSize:    Size{100, 50},
						Text:       Bind("Remarks"),
					},

					Label{
						ColumnSpan: 2,
						Text:       "Patience:",
					},
					//单行文本框的设置
					LineEdit{
						ColumnSpan: 2,
						Text:       Bind("PatienceField"),
					},

				},
			},
			Composite{
				//横向布局
				Layout: HBox{},
				Children: []Widget{
					//加入一个横向空间
					HSpacer{},
					PushButton{
						AssignTo: &acceptPB,
						Text:     "OK",
						OnClicked: func() {
							//提交按钮的动作
							if err := db.Submit(); err != nil {
								log.Print(err)
								return
							}

							dlg.Accept()
						},
					},
					PushButton{
						AssignTo:  &cancelPB,
						Text:      "Cancel",
						OnClicked: func() { dlg.Cancel() },
					},
				},
			},
		},
	}.Run(owner)
}
